Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

MySQL — выборка из графа — оптимизация (Антон Макаренко)
Author Message
Антон Макаренко
Участник форума



Joined: 05 Feb 2004
Posts: 374
Карма: 34
   поощрить/наказать

Location: Киев

PostPosted: Fri Dec 16, 2005 5:55 pm (написано за 12 минут 43 секунды)
   Post subject: MySQL — выборка из графа — оптимизация
Reply with quote

Добрый вечер.
Вопрос об оптимизации запросов из двух таблиц.

Есть 2 таблицы (MyISAM):
users (user_id*, ...)
networks (uid1, uid2) — неориентированный граф (связи между юзерами), где uid1, uid2 берутся из users.user_id. Идентификатор может находиться как в поле uid1, так и в uid2. (записей будет очень много)
Например, 1й связан с 3м, 3й со 2м, 4й с 1м:
Code (any language): скопировать код в буфер обмена
networks
   uid1   uid2
   1      3
   3      2
   4      1
Нужно получить инфу о юзерах, которые связаны с определённым user_id (скажем, с 1). У меня это получилось двумя способами:

Code (SQL): скопировать код в буфер обмена
--EXPLAIN
SELECT * FROM
      (
       SELECT
          IF(uid1=1,uid2,uid1) AS "fld"
       FROM
           networks
       WHERE
            uid1=1
            OR
            uid2=1
      ) nw
INNER JOIN
     users u
     ON
     u.user_id = nw.fld
Code (SQL): скопировать код в буфер обмена
--EXPLAIN
SELECT
      *
FROM
    users
WHERE
     user_id IN (
     SELECT
           IF (uid1=1,uid2,uid1)
     FROM
         networks
     WHERE
          uid1=1
          OR
          uid2=1
     )
Какой запрос будет работать быстрее?
Не проще ли сделать 2 запроса последовательно?
Или можно сделать вообще иначе?
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sat Dec 17, 2005 2:13 pm (спустя 20 часов 17 минут; написано за 1 минуту 39 секунд)
   Post subject:
Reply with quote

Не нужно никаких вложенных запросов.
Code (SQL): скопировать код в буфер обмена
SELECT *
FROM
  networks n
  JOIN users u ON (u.id=n.uid1 OR u.id=uid2) AND u.id!=$n
WHERE
  n.uid1=$n OR n.uid2=$n
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Sat Dec 17, 2005 2:14 pm (спустя 1 минуту 14 секунд; написано за 57 секунд)
   Post subject:
Reply with quote

P.S.
Ух ты! Оказывается, если писать все маленькими буквами и обернуть в {sql}...{/sql}, подсветчик синтаксиса ключевые слова автоматом переводит в верхний регистр. Удобно!
Back to top
View user's profile Send private message Send e-mail
Антон Макаренко
Участник форума



Joined: 05 Feb 2004
Posts: 374
Карма: 34
   поощрить/наказать

Location: Киев

PostPosted: Mon Dec 19, 2005 5:19 pm (спустя 2 дня 3 часа 5 минут; написано за 1 минуту 44 секунды)
   Post subject:
Reply with quote

Дмитрий Котеров:
В очередной раз Вы меня просвещаете. Спасибо большое [+1]

Порекомендуете книгу, которая научит мыслить "в стиле SQL"?
Или вообще *мыслить* в принципе? :-)
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Tue Dec 20, 2005 2:30 pm (спустя 21 час 11 минут; написано за 13 секунд)
   Post subject:
Reply with quote

Купите самую толстую по SQL, какую найдете.
Back to top
View user's profile Send private message Send e-mail
Антон Макаренко
Участник форума



Joined: 05 Feb 2004
Posts: 374
Карма: 34
   поощрить/наказать

Location: Киев

PostPosted: Thu Dec 22, 2005 6:30 pm (спустя 2 дня 3 часа 59 минут; написано за 7 минут 53 секунды)
   Post subject:
Reply with quote

SQL-запрос, выбирающий юзверей, связанных с определённой группой (множеством), а также их количество.
Может пригодится кому:
Code (SQL): скопировать код в буфер обмена
SELECT
        u.*,
        (
                SELECT COUNT(*)
                FROM networks
                WHERE (u.user_id IN (uid1,uid2))
        ) AS "quantity"
FROM users u JOIN networks n ON
                ((n.uid1 IN (X)) OR (n.uid2 IN(X)))
                AND
                (u.user_id NOT IN (X))
                AND
                (u.user_id IN (n.uid1,n.uid2))
Где X -- некоторое множество вершин (например, множество из одного элемента, как вырожденный случай).

PS или зачем это надо
Если в виде графа организована система рефералов (в данном случае, ненаправленная система), то
выполняя этот запрос несколько раз каскадно (или рекурсивно), можно "добраться" до рефералов любого колена относительно определённого юзера.
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 413
   поощрить/наказать


PostPosted: Fri Dec 23, 2005 1:18 pm (спустя 18 часов 47 минут; написано за 42 секунды)
   Post subject:
Reply with quote

Любите ж Вы вложенные подзапросы, ну что ты будешь делать. :-)
То же самое можно написать и через GROUP BY. Но, конечно, будет менее читабельно - зато работает в MySQL 3 и 4.0.
Back to top
View user's profile Send private message Send e-mail
Константин Жинько [tIT]
Сотрудник «Лаборатории»



Joined: 12 Jun 2004
Posts: 2264
Карма: 106
   поощрить/наказать

Location: Москва

PostPosted: Wed Jan 04, 2006 4:51 am (спустя 11 дней 15 часов 33 минуты; написано за 41 секунду)
   Post subject:
Reply with quote

Антон Макаренко wrote:
Порекомендуете книгу, которая научит мыслить "в стиле SQL"?
Граббера почитайте.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Page 1 of 1    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML